spb/autoscholar
Public
1"use client";2import { useRouter } from "next/navigation";3import { type FormEvent, useState } from "react";4import { useToast } from "@/components/Toast";5import { type ApiError, api } from "@/lib/client/api";67export function OverrideForm({ runId, gates }: { runId: string; gates: string[] }) {8 const router = useRouter();9 const toast = useToast();10 const [busy, setBusy] = useState(false);11 return (12 <form13 className="mt-2 space-y-2"14 onSubmit={async (e: FormEvent<HTMLFormElement>) => {15 e.preventDefault();16 setBusy(true);17 try {18 await api(`/api/admin/quality/${runId}/override`, {19 json: { rationale: new FormData(e.currentTarget).get("rationale") },20 });21 toast.push("success", "Override recorded; run now awaits explicit publication.");22 router.refresh();23 } catch (err) {24 toast.push("error", (err as ApiError).message);25 } finally {26 setBusy(false);27 }28 }}29 >30 <p className="muted text-sm">31 Overriding: <code className="text-xs">{gates.join(", ")}</code>. The rationale is permanently recorded32 in the audit log and the publication decision.33 </p>34 <label htmlFor="rationale" className="label">35 Rationale (min 20 characters)36 </label>37 <textarea id="rationale" name="rationale" required minLength={20} rows={3} className="input" />38 <button type="submit" className="btn btn-danger" disabled={busy}>39 Record override40 </button>41 </form>42 );43}44